package com.yfqy.app.modules.order.builder;

import com.yfqy.app.domain.entity.Customer;
import com.yfqy.app.domain.entity.ProductSku;
import com.yfqy.app.domain.entity.ProductSpu;
import com.yfqy.app.domain.entity.PromotionProduct;
import com.yfqy.app.domain.entity.PromotionRule;
import com.yfqy.app.enums.OrderType;
import com.yfqy.app.exception.BusinessException;
import com.yfqy.app.modules.order.dto.LockedStockDTO;
import com.yfqy.app.modules.order.dto.OrderAmountDTO;
import com.yfqy.app.modules.order.dto.OrderCreateRequest;
import com.yfqy.app.modules.order.dto.OrderInfoDTO;
import com.yfqy.app.modules.order.dto.OrderItemRequest;
import com.yfqy.app.modules.order.dto.PointsDeductionDTO;
import com.yfqy.app.modules.system.dto.DeductionDTO;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

public interface OrderCreateBuilder {


    /**
     * 订单类型
     *
     * @return
     */
    OrderType getOrderType();

    /**
     * 校验订单基础参数
     *
     * @param request
     */
    void validateParams(OrderCreateRequest request);

    /**
     * 普通订单类型校验，校验商品和库存
     *
     * @param request 订单创建请求
     * @throws BusinessException 当商品校验不通过时抛出
     */
    void validateProducts(OrderCreateRequest request);

    /**
     * 独属于促销活动的特殊校验
     *
     * @param request
     */
    void specificValidate(OrderCreateRequest request);

    /**
     * 校验促销商品是否限购
     *
     * @param item
     * @param customerId
     * @param promotionProduct
     */
    void validatePurchaseLimit(OrderItemRequest item, Long customerId, PromotionProduct promotionProduct);

    Map<Long, ProductSpu> validateProductInfo(OrderItemRequest item);

    /**
     * 验证并获取促销活动商品
     *
     * @param promotionId
     * @param skuId
     * @return
     */
    PromotionProduct getAndValidatePromotion(Long promotionId, Long skuId);

    /**
     * 批量获取并验证SPU
     */
    Map<Long, ProductSpu> batchGetAndValidateSpus(List<Long> spuIds);

    /**
     * 批量获取并验证SKU
     */
    Map<Long, ProductSku> batchGetAndValidateSkus(List<Long> skuIds, Map<Long, ProductSpu> spuMap);


    /**
     * 单Sku商品校验商品价格
     *
     * @param item
     * @param spuMap
     * @param promotionProduct
     */
    void validatePrice(OrderItemRequest item, Map<Long, ProductSpu> spuMap, PromotionProduct promotionProduct);

    /**
     * 多Sku商品校验商品价格
     *
     * @param items
     * @param spuMap
     * @param skuMap
     */
    void validatePrice(List<OrderItemRequest> items, Map<Long, ProductSpu> spuMap, Map<Long, ProductSku> skuMap);

    /**
     * 单Sku商品校验商品库存
     *
     * @param item
     * @param spuMap
     * @param promotionProduct
     */
    void validateStock(OrderItemRequest item, Map<Long, ProductSpu> spuMap, PromotionProduct promotionProduct);

    /**
     * 多Sku商品校验商品库存
     *
     * @param items
     * @param spuMap
     * @param skuMap
     */
    void validateStock(List<OrderItemRequest> items, Map<Long, ProductSpu> spuMap, Map<Long, ProductSku> skuMap);


    /**
     * 填充商品Sku信息
     *
     * @param item
     * @param spuMap
     * @param productSku
     */
    void completeSku(OrderItemRequest item, Map<Long, ProductSpu> spuMap, ProductSku productSku);

    /**
     * 填充商品Sku信息
     *
     * @param items
     * @param spuMap
     * @param skuMap
     */
    void completeSku(List<OrderItemRequest> items, Map<Long, ProductSpu> spuMap, Map<Long, ProductSku> skuMap);

    /**
     * 计算订单金额
     *
     * @param request
     * @return
     */
    OrderAmountDTO calculateAmount(OrderCreateRequest request);

    /**
     * 扣除库存
     *
     * @param request
     * @return
     */
    LockedStockDTO lockStock(OrderCreateRequest request);

    /**
     * 保存订单数据
     *
     * @param orderInfoDTO
     */
    void saveOrder(OrderInfoDTO orderInfoDTO);

    /**
     * 订单创建后的其他任务
     *
     * @param points
     * @param userId
     * @param orderId
     * @param payExpireTime
     */
    void afterOrderCreated(int points, long userId, Long orderId, Date payExpireTime);

    /**
     * 获取积分抵扣规则
     *
     * @return
     */
    DeductionDTO getPointsDeductionConfig();

    /**
     * 获取满减配置
     *
     * @return
     */
    PromotionRule getFullDiscountRule();

    /**
     * 获取拼团规则配置
     *
     * @return
     */
    PromotionRule getGroupRule();

    /**
     * 获取折扣规则配置
     *
     * @return
     */
    PromotionRule getDiscountRule();

    /**
     * 使用积分是否开启
     *
     * @param deductionDTO
     * @return
     */
    boolean isPointsDeductionEnabled(DeductionDTO deductionDTO);

    /**
     * 应用积分抵扣逻辑
     *
     * @param amountDTO     订单金额DTO（会被修改）
     * @param paymentAmount 可抵扣的金额基数（通常是优惠后的金额）
     */
    void applyPointsDeduction(OrderAmountDTO amountDTO, BigDecimal paymentAmount);

    /**
     * 当前用户
     *
     * @return
     */
    Customer getCurrentCustomer();

    /**
     * 计算最优的积分使用
     *
     * @param paymentAmount
     * @param points
     * @param config
     * @return
     */
    PointsDeductionDTO calculateOptimalDeduction(BigDecimal paymentAmount, int points, DeductionDTO config);


    /**
     * 应用积分抵扣金额
     *
     * @param amountDTO
     * @param deduction
     */
    void applyDeductionToAmount(OrderAmountDTO amountDTO, PointsDeductionDTO deduction);

    /**
     * 计算订单是否需要运费
     *
     * @param amountDTO
     */
    void calculateFreightAmount(OrderAmountDTO amountDTO);
}
